﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Diagnostics;


namespace SharedGamesClasses {

    /// <summary>
    /// TwentyOne.cs plays the game of Twenty One - 
    /// a card game whereby two parties compete to get a hand of playing cards
    /// whose summed facevalues are closest to 21, without exceeding it.
    /// 
    /// Version May 2012 Jim Reye 
    /// 
    /// </summary>
    public static class TwentyOne {
        public const int NUM_OF_PLAYERS = 2;
        public const int USER = 0;
        public const int DEALER = 1;

        private const string USERS_NAME = "Player";
        private const string DEALERS_NAME = "Dealer";
        private const string HIT_OR_STAND = "Player Hit (H) or Stand (S): ";
        private const string ACE_VALUE = "Enter number of Ace count as 1: ";
        private const string PLAY_AGAIN = "Another Game? <Y or N> ";
        private const int NUM_OF_STARTING_CARDS = 2;

        // More constants and/or class variables may be needed.

        private static CardPile cardPile = new CardPile(true);
        public static Hand[] hands = new Hand[NUM_OF_PLAYERS];
        private static int[] pointsTotal = new int[NUM_OF_PLAYERS] { 0, 0 };
        public static int[] numOfGamesWon = new int[NUM_OF_PLAYERS] { 0, 0 };

        private static int numOfUserAcesWithValueOne;

        /// <summary>
        /// Set up to play the game, 
        /// by shuffling the pile of cards and dealing the two hands.
        /// </summary>
        public static void SetUpGame() {
            cardPile.Shuffle();
            hands[USER] = new Hand(cardPile.DealCards(NUM_OF_STARTING_CARDS));
            hands[DEALER] = new Hand(cardPile.DealCards(NUM_OF_STARTING_CARDS));
            numOfUserAcesWithValueOne = 0;
        } //end SetUpGame
        public static void ResetGame()
        {
            SetUpGame();

            pointsTotal[USER] = 0;
            pointsTotal[DEALER] = 0;
        }

        /// <summary>
        /// Plays the game of Twenty One until the user decides to stop.
        /// </summary>
        public static void PlayConsole()
        {

            int isUserWin = -1;
            char isPlayAgain = 'y';
            while (isPlayAgain == 'y')
            {
                ResetGame();
                
                DisplayHand(USER);
                DisplayHand(DEALER);

                pointsTotal[DEALER] += ReturnPoint(hands[DEALER].GetCard(0).GetFaceValue()) + ReturnPoint(hands[DEALER].GetCard(1).GetFaceValue());
                if (pointsTotal[DEALER] == 21)
                {
                    Console.WriteLine("Dealer Win ( " + pointsTotal[DEALER].ToString() + " point ) - Dealer Win");
                    numOfGamesWon[DEALER]++;
                    Console.WriteLine("Dealer have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                    Console.Write(PLAY_AGAIN);
                    isPlayAgain = Char.Parse(Console.ReadLine());
                    break;
                }

                if (NumAce() > 0)
                {
                    Console.WriteLine("Enter the value of this Ace <1 or 11>: ");
                    int AceValue = int.Parse(Console.ReadLine());
                    if (AceValue == 1)
                    {
                        numOfUserAcesWithValueOne++;
                    }
                }
                
                Console.Write(HIT_OR_STAND);
                char isUserHit = Char.Parse(Console.ReadLine());
                while (isUserHit == 'h')
                {
                    UserHitCard();
                    DisplayHand(USER);
                    if (hands[USER].GetCard(hands[USER].GetCount() - 1).GetFaceValue() == FaceValue.Ace)
                    {
                        Console.WriteLine("Enter the value of this Ace <1 or 11>: ");
                        int AceValue = int.Parse(Console.ReadLine());
                        if (AceValue == 1)
                        {
                            numOfUserAcesWithValueOne++;
                        }
                    }
                    CountUserPoint();
                    if (pointsTotal[USER] > 21)
                    {
                        Console.WriteLine("You have gone bust ( " + pointsTotal[USER].ToString() + " point ) - Dealer Win");
                        numOfGamesWon[DEALER]++;
                        Console.WriteLine("You have won " + numOfGamesWon[USER].ToString() + " games and I have won " + numOfGamesWon[DEALER].ToString() + " games");
                        Console.Write(PLAY_AGAIN);
                        isPlayAgain = Char.Parse(Console.ReadLine());
                        
                        break;
                    }
                    Console.Write(HIT_OR_STAND);
                    isUserHit = Char.Parse(Console.ReadLine());
                    CountUserPoint();
                }
                if (isUserHit == 's')
                {
                    CountUserPoint();
                    switch (IsDealerWin())
                    {
                        case 1:
                            {
                                Console.WriteLine("Dealer Win ( " + pointsTotal[DEALER].ToString() + " point ) - Dealer Win");
                                numOfGamesWon[DEALER]++;
                                Console.WriteLine("Dealer have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                                Console.Write(PLAY_AGAIN);
                                isPlayAgain = Char.Parse(Console.ReadLine());
                            }
                            break;
                        case 0:
                            {
                                Console.WriteLine("Both Win!");
                                numOfGamesWon[DEALER]++;
                                numOfGamesWon[USER]++;
                                Console.WriteLine("Dealer have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                                Console.Write(PLAY_AGAIN);
                                isPlayAgain = Char.Parse(Console.ReadLine());
                            }
                            break;
                        case -1:
                            {
                                Console.WriteLine("Dealer have gone bust ( " + pointsTotal[DEALER].ToString() + " point ) - you Win");
                                numOfGamesWon[USER]++;
                                Console.WriteLine("You have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                                Console.Write(PLAY_AGAIN);
                                isPlayAgain = Char.Parse(Console.ReadLine());
                            }
                            break;
                            
                    }
                }
                // Play 21 until the user decides to stop.
            }
            ResetGame();
            numOfGamesWon[USER] = 0;
            numOfGamesWon[DEALER] = 0;
        }//end PlayConsole

        public static int Deal()
        {            
            ResetGame();
            cardPile.Shuffle();

            DisplayHand(USER);
            DisplayHand(DEALER);

            pointsTotal[DEALER] += ReturnPoint(hands[DEALER].GetCard(0).GetFaceValue()) + ReturnPoint(hands[DEALER].GetCard(1).GetFaceValue());
            CountUserPoint();
            if (pointsTotal[DEALER] == 21)
            {
                Trace.WriteLine("Dealer Win ( " + pointsTotal[DEALER].ToString() + " point ) - Dealer Win");
                numOfGamesWon[DEALER]++;
                Trace.WriteLine("Dealer have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                return -1;
            }

            if (NumAce() > 0)
            {
                return 0;
            }
            return 1;
        }

        public static bool Hit()
        {
            UserHitCard();
            DisplayHand(USER);
            if (hands[USER].GetCard(hands[USER].GetCount() - 1).GetFaceValue() == FaceValue.Ace)
            {
                return false;
            }
                        
            return true;
        }

        public static bool isBustedPlayer()
        {
            CountUserPoint();

            if (pointsTotal[USER] > 21)
            {
                Trace.WriteLine("You have gone bust ( " + pointsTotal[USER].ToString() + " point ) - Dealer Win");
                numOfGamesWon[DEALER]++;
                Trace.WriteLine("You have won " + numOfGamesWon[USER].ToString() + " games and I have won " + numOfGamesWon[DEALER].ToString() + " games");
                return true;
            }

            return false;
        }

        public static int Stand()
        {
            CountUserPoint();

            switch (IsDealerWin())
            {
                case 1:
                    Trace.WriteLine("Dealer Win ( " + pointsTotal[DEALER].ToString() + " point ) - Dealer Win");
                    numOfGamesWon[DEALER]++;
                    Trace.WriteLine("Dealer have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                    return 1;
                    break;
                case 0:
                    Trace.WriteLine("Both Win!");
                    numOfGamesWon[DEALER]++;
                    numOfGamesWon[USER]++;
                    Trace.WriteLine("Dealer have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                    return 0;
                    break;
                case -1:
                    Trace.WriteLine("Dealer have gone bust ( " + pointsTotal[DEALER].ToString() + " point ) - you Win");
                    numOfGamesWon[USER]++;
                    Trace.WriteLine("You have won " + numOfGamesWon[DEALER].ToString() + " games and I have won " + numOfGamesWon[USER].ToString() + " games");
                    return -1;
                    break;
                default:
                    return -1;
                    break;
            }
        }

        /// <summary>
        /// Output the hand of cards of either the User or the Dealer
        ///  using DisplayHand of Hand class
        /// Pre: hands initialised
        /// Post: Displays the hand of cards held by the specified player.
        /// </summary>
        public static void DisplayHand(int player) {
            if (player == USER)
            {
                Trace.Write("You have ");
                hands[player].DisplayHand(false, false);
            }
            else {
                Trace.Write("Dealer has ");
                hands[player].DisplayHand(false, false);
            }
            Trace.WriteLine("");
        } // end DisplayHand

        public static int ReturnPoint(FaceValue facevalue)
        {
            switch (facevalue)
            {
                case FaceValue.Two:
                    return 2;
                case FaceValue.Three:
                    return 3;
                case FaceValue.Four:
                    return 4;
                case FaceValue.Five:
                    return 5;
                case FaceValue.Six:
                    return 6;
                case FaceValue.Seven:
                    return 7;
                case FaceValue.Eight:
                    return 8;
                case FaceValue.Nine:
                    return 9;
                case FaceValue.Ten:
                    return 10;
                case FaceValue.Jack:
                    return 10;
                case FaceValue.King:
                    return 10;
                case FaceValue.Queen:
                    return 10;
                default:
                    return 11;
            }
        }
        public static int NumAce()
        {
            int numAce = 0;
            for (int i = 0; i < hands[USER].GetCount(); i++)
            {
                if (hands[USER].GetCard(i).GetFaceValue() == FaceValue.Ace)
                    numAce++;
            }
            return numAce;
        }
        public static void CountUserPoint()
        {
            pointsTotal[USER] = 0;
            pointsTotal[USER] += numOfUserAcesWithValueOne * 1 + (NumAce() - numOfUserAcesWithValueOne) * 11;
         
            for (int i = 0; i < hands[USER].GetCount(); i++)
            {
                if (hands[USER].GetCard(i).GetFaceValue() == FaceValue.Ace)
                { }
                else
                {
                    pointsTotal[USER] += ReturnPoint(hands[USER].GetCard(i).GetFaceValue());
                }
            }
        }
      
        public static int IsDealerWin()
        {
            int isWin = 0; ;
            pointsTotal[DEALER] = 0;
            pointsTotal[DEALER] += ReturnPoint(hands[DEALER].GetCard(0).GetFaceValue()) + ReturnPoint(hands[DEALER].GetCard(1).GetFaceValue());
            if (pointsTotal[DEALER] >= 17)
            {
                if (pointsTotal[DEALER] > pointsTotal[USER])
                    isWin = 1;
                if (pointsTotal[DEALER] == pointsTotal[USER])
                    isWin = 0;
            }
            else
            {
                while (pointsTotal[DEALER] < 17 || pointsTotal[DEALER] < pointsTotal[USER])
                {
                    Card hitCard = cardPile.DealOneCard();
                    hands[DEALER].Add(hitCard);
                    pointsTotal[DEALER] += ReturnPoint(hitCard.GetFaceValue());
                }
                if (pointsTotal[DEALER] > 21)
                    isWin = -1;
                else { 
                    if(pointsTotal[DEALER] == pointsTotal[USER])
                        isWin = 0;
                    if(pointsTotal[DEALER] > pointsTotal[USER])
                        isWin = 1;
                }
              
            }
            return isWin;
        }
        public static void UserHitCard()
        {
            Card hitCard = cardPile.DealOneCard();
            hands[USER].Add(hitCard);

        }

        /* The following methods are intended to be called by your GUI code.
         * I.e. you shouldn't need them when writing your Console game,
         * but do not delete them. */

        /// <summary>
        /// Helps the GUI to display what is in a player's hand.
        /// </summary>
        /// <returns>the Hand of the specified player</returns>
        public static Hand GetHand(int player) {
            return hands[player];
        }

        /// <summary>
        /// Helps the GUI to display the number of Aces that 
        /// the user has chosen to have value 1, rather than 11.
        /// </summary>
        /// <returns>the numOfUserAcesWithValueOne</returns>
        public static int GetNumOfUserAcesWithValueOne() {
            return numOfUserAcesWithValueOne;
        }

        /// <summary>
        /// Helps the GUI to display the points total of each player.
        /// </summary>
        /// <returns>the points total of the specified player</returns>
        public static int GetPointsTotal(int player) {
            return pointsTotal[player];
        }

        /// <summary>
        /// Helps the GUI to display the number of games won by each player.
        /// </summary>
        /// <returns>the number of games won by the specified player</returns>
        public static int GetNumOfGamesWon(int player) {
            return numOfGamesWon[player];
        }

        /// <summary>
        /// Helps the GUI to increase the number of Aces that 
        /// the user has chosen to have value 1, rather than 11.
        /// </summary>
        /// <returns>the numOfUserAcesWithValueOne</returns>
        public static int IncreaseNumOfUserAcesWithValueOne()
        {
            numOfUserAcesWithValueOne += 1;
            return numOfUserAcesWithValueOne;
        }


    } //end class TwentyOne
} //end namespace
